#include "algorithm_random.h"

namespace utils {
std::mt19937 &AlgorithmRandom::GetRandomEngine()
{
    thread_local std::random_device rd;
    thread_local std::mt19937 gen(rd());
    return gen;
}

template<std::integral T>
T AlgorithmRandom::GenerateNumber(T minValue, T maxValue)
{
    std::uniform_int_distribution<T> dist(minValue, maxValue);
    return dist(GetRandomEngine());
}

template<std::floating_point T>
T AlgorithmRandom::GenerateNumber(T minValue, T maxValue)
{
    std::uniform_real_distribution<T> dist(minValue, maxValue);
    return dist(GetRandomEngine());
}

int32_t AlgorithmRandom::GenerateInt32(const Int32Config &config)
{
    return GenerateNumber(config.minValue, config.maxValue);
}

std::string AlgorithmRandom::GenerateString(const StringConfig &config)
{
    const int32_t length = GenerateNumber(config.minLength, config.maxLength);
    std::string result;
    result.reserve(static_cast<size_t>(length));
    for ([[maybe_unused]] auto&& i : std::views::iota(0, length)) {
        result.push_back(config.charSet[GenerateNumber<size_t>(0, config.charSet.size() - 1)]);
    }
    return result;
}

std::unique_ptr<TreeNode> AlgorithmRandom::GenerateBinaryTree(const TreeConfig &config)
{
    return GenerateTreeRecursive(config, 1);
}

std::unique_ptr<TreeNode> AlgorithmRandom::GenerateTreeRecursive(const TreeConfig &config, size_t currentDepth)
{
    if (currentDepth > config.maxDepth || 
        (currentDepth >= config.minDepth && GenerateNumber(0, 1) == 0)) {
        return nullptr;
    }

    auto node = std::make_unique<TreeNode>(GenerateNumber(config.minValue, config.maxValue));
    node->left = GenerateTreeRecursive(config, currentDepth + 1);
    node->right = GenerateTreeRecursive(config, currentDepth + 1);

    return node;
}
} // namespace utils